package org.listbeast.core.filters;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Collection;

import org.apache.log4j.Logger;
import org.listbeast.core.dataobjects.Song;
import org.listbeast.core.dataobjects.SongCollection;
import org.listbeast.core.dataobjects.SongCollectionImpl;
import org.listbeast.core.dataobjects.YoutubeSong;
import org.listbeast.core.filters.algorithms.SongMatchingAlgorithm;

public class SongFilter {

	private static final Logger LOG = Logger.getLogger(SongFilter.class);

	private SongMatchingAlgorithm matcher;

	private static FileWriter fstream;
	private static BufferedWriter writer;

	public SongFilter(SongMatchingAlgorithm matcher) {
		this.matcher = matcher;
	}

	/**
	 * The algorithm performs a search in two song collections to find possible
	 * matches. The arguments order is important for performance reasons, and
	 * this is why the second collection needs to be youtube songs and the first
	 * can be either youtube or disk songs (the latter can be many)
	 * 
	 * @param songCollection1
	 *            Collection of songs that need to be searched for matches (e.g.
	 *            disk songs)
	 * @param songCollection2
	 *            Collection of songs that need to be matched! (e.g. youtube
	 *            songs)
	 * @return
	 */
	public <E extends Song, K extends YoutubeSong> SongCollection<E> findMatches(SongCollection<E> songCollection1, SongCollection<K> songCollection2) {

		initIO();
		
		SongCollection<E> matchedSongs = new SongCollectionImpl<E>();

		Collection<String> artists = songCollection2.getArtistNames();
		for (String collection2artist : artists) { //for every artist
			String collection1artist = collection2artist;
			for (K collection2song : songCollection2.getArtistSongs(collection2artist)) { // for every youtube song
				boolean songInCollection1found = false;
				for (E collection1song : songCollection1.getArtistSongs(collection1artist)) { //for every disk or youtube song
					boolean match = matcher.compareSongs(collection1song, collection2song);
					if (match) {
						writeLog(collection2song.getTitle(), collection1song.getTitle(), collection1song.getArtistName(), match);

						if (!songInCollection1found) {
							songInCollection1found = true;
							matchedSongs.addSong(collection1song);

						} else {
							//important! in case there is a match, we do not want to retrieve and add in our playlist other 
							//disk songs that have same title as the youtube song but are from other albums or lives etc. 
							LOG.info("Skipping file "
									+ collection1song.toString()
									+ " to avoid duplicates.");
						}
					}
				}

			}
		}

		closeIO();
		
		return matchedSongs;
	}

	/**
	 * 
	 * @param songCollection
	 *            search song collection for potential match of
	 * @param songToMatch
	 *            this item
	 * @return boolean representing whether the song has been matched with at
	 *         least one item of the list or not
	 */
	public <E extends Song, K extends YoutubeSong> boolean findMatch(SongCollection<E> songCollection, K songToMatch) {

		String artist = songToMatch.getArtistName();

		if (songCollection.getArtistSongs(artist) != null) {
			for (E collection1song : songCollection.getArtistSongs(artist)) { //for every disk song
				boolean match = matcher.compareSongs(collection1song, songToMatch);
				if (match) {
					return true;
				}
			}
		}
		return false;
	}

	private void writeLog(String songToMatch, String collectionSongTitle, String collectionSongArtist, boolean match) {

		LOG.debug("For collection song (" + collectionSongTitle
				+ ") and song to match (" + songToMatch
				+ ") matching algorithm returned " + match + ".");

		LOG.info("findSong(): Found song (" + collectionSongTitle
				+ ") when compared with song to match (" + songToMatch + ").");

		appendToFile(collectionSongArtist, collectionSongTitle, songToMatch);

	}

	private static void initIO() {
		try {
			fstream = new FileWriter("testInputData.txt");
			writer = new BufferedWriter(fstream);
		} catch (IOException e) {
			LOG.error("appendToFile(): Error: " + e.getMessage());
		}
	}

	private static void closeIO() {
		try {
			writer.close();
		} catch (IOException e) {
			LOG.error("appendToFile(): Error: " + e.getMessage());
		}
	}

	private void appendToFile(String artistName, String libraryTitle, String youtubeTitle) {

		try {
			writer.write(artistName + "::::" + libraryTitle + "::::"
					+ youtubeTitle + "::::");
			writer.newLine();
		} catch (IOException e) {
			LOG.error("appendToFile(): Error: " + e.getMessage());
		}
	}
}

/*
 * private boolean applyRule2(String libraryTitle, String youtubeTitle) {
 * 
 * String libraryTitleTemp = libraryTitle.replaceAll("[^a-zA-Z_\\- ]+", "");
 * String libraryTitleTemp2 = libraryTitleTemp.replaceAll("[_\\-]+", " ");
 * String libraryTitleTemp3 = libraryTitleTemp2.replaceAll("^[ ]+", "");
 * 
 * if (youtubeTitle.matches(".*" + libraryTitleTemp3 + ".*")) { return true; }
 * else { return false; } }
 */

/*
 * public boolean findSong(String artistName, String libraryTitle, List<String>
 * youtubeSongList) {
 * 
 * boolean rule1 = false; boolean rule2 = false;
 * 
 * for (String youtubeTitle : youtubeSongList) {
 * 
 * //rule1 = applyRule1(artistName, libraryTitle, youtubeTitle);
 * 
 * // rule2 = applyRule2(libraryTitle, youtubeTitle);
 * log.debug("For library song (" + libraryTitle + ") and youtube song (" +
 * youtubeTitle + ") rule 1 is (" + rule1 + ") and rule2 is (" + rule2 + ").");
 * 
 * if (rule1 || rule2) { // if one rule is true then it returns true
 * log.info("findSong(): Found song (" + libraryTitle +
 * ") when compared with youtube song (" + youtubeTitle + ").");
 * appendToFile(artistName, libraryTitle, youtubeTitle); return true; } } return
 * false; }
 */

